
//package ProjetoGeral.ParaAmbos;

//import ProjetoGeral.Cliente.Arquivo;
import java.net.*; // Para Socket
import java.io.*; // Para IOException e Input/OutputStream
import java.nio.channels.FileChannel;
import java.util.Scanner;
import java.net.InetAddress;
import java.util.Date;


public class TCPEchoClient{
    private char comando;
    private String nomeArquivo;
    private String mensagem;
    private StringBuffer mensagemRequisicaoArquivo;
    private static final int tamanho_buffer = 4096;
    private Date time0;
    private long TIME0;
    private Date time1;
    private long TIME1;
    
    
      
    public String enviaRequisicao (String server, String nomeArq, int servPort) throws IOException{

            StringBuffer nodeArquivo = new StringBuffer();
            byte[] byteBuffer = nomeArq.getBytes(); // Converte String de entrar para bytes codificacao padrao 
            
            // Cria o socket que sera utilizado para se conectar ao servidor na porta especificada
            Socket socket = new Socket(server, servPort);

            System.out.println("Conectado ao servidor... enviando a mensagem");

            InputStream in = socket.getInputStream();

            OutputStream out = socket.getOutputStream();

            out.write(byteBuffer); // Envia a mensagem codificada ao servidor

            // Recebe a mesma mensagem de volta 
            int totalBytesRcvd = 0;
            int bytesRcvd;
            while (totalBytesRcvd < byteBuffer.length) {
                    if ((bytesRcvd = in.read(byteBuffer, totalBytesRcvd, byteBuffer.length - totalBytesRcvd)) == -1)
                            throw new SocketException("Conexao fechada inesperadamente");
                    totalBytesRcvd += bytesRcvd;
            }

            System.out.println("Mensagem recebida com sucesso!");

            //Recebe a resposta do servidor e guarda em nodeArquivo
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            InputStreamReader isr = new InputStreamReader(bis, "US-ASCII");

            int c;
            while ( (c = isr.read()) != 13)
                nodeArquivo.append( (char) c);

            socket.close();
            System.out.println("O arquivo está em: " + nodeArquivo);

            //retorna o nó onde está o arquivo
            return(nodeArquivo.toString());
    }

    private Socket estabelecerConexao(String host, int port) throws UnknownHostException, IOException{
        InetAddress address = InetAddress.getByName(host);
        Socket connection = new Socket(host, port);
        System.out.println("SocketClient initialized");
        return connection;
    }
    
        private String requisicaoNomeNodeDestino(Socket connection) throws IOException{
        String nodeDestino;
        
        BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
        InputStreamReader isr = new InputStreamReader(is);//Para recepcao de dados
        int character;
        StringBuffer nodeRecebido = new StringBuffer();
        //Pega o nome do arquivo
        while((character = isr.read()) != (int)'#') {//A '#' indica o final do nome do arquivo
            nodeRecebido.append((char)character);
        }
        nodeDestino = nodeRecebido.toString();
        System.out.println(nodeDestino);
        return nodeDestino;
    }
    
    private void enviarNomeArquivoParaNodeDestino(Socket connection, String mensagemAEnviar) throws IOException{
        BufferedOutputStream os = new BufferedOutputStream(connection.getOutputStream());
        OutputStreamWriter saida = new OutputStreamWriter(os, "US-ASCII");

        saida.write(mensagemAEnviar);//Enviando o dado...
        System.out.println(mensagemAEnviar);
        saida.flush();
    }

    private void tomarDecisao(char c, String nome, String nodeDestino, Socket connection) throws IOException {
        //Essas funcoes ocorrem a após conseguir o node de destino com o MESTRE****************
        if(c == 'L'){//só enviar ele para o node que fez a requisicao
            this.recebeArquivo(nome, connection);
            this.leituraArquivo(nome);
        }
        if(c == 'E'){//apagar o arquivo e mandar um feedback para o nodeMestre excluir o arquivo da lista
            this.enviarArquivo(nome, nodeDestino, connection);
        }
        if(c == 'M'){//mover o arquivo desse local para o node requisitante
            this.criarArquivo(nome);               
        }
        
    }

    private void criarArquivo(String nome) throws IOException {
        File arquivo = new File("CCC"+nome);

        if(arquivo.exists() == false){
            boolean createNewFile = arquivo.createNewFile();
        }
    }

    private void enviarArquivo(String nome, String nodeDestino, Socket connection) throws IOException {
        ObjectOutputStream saida = new ObjectOutputStream(connection.getOutputStream());
        FileInputStream file = new FileInputStream(nome);
        byte[] buffer = new byte[this.tamanho_buffer]; //tamanho do arquivo = 4K

        while(true){
            int tamanho_file = file.read(buffer);
            if(tamanho_file == -1)break;
            saida.write(buffer, 0, tamanho_file);
        }
        file.close();
    }

    private void recebeArquivo(String nome, Socket connection) throws IOException {
        ObjectInputStream receber = new ObjectInputStream(connection.getInputStream());
        FileOutputStream file = new FileOutputStream(nome);
        byte[] buffer = new byte[TCPEchoClient.tamanho_buffer]; //tamanho do arquivo = 4K

        while(true){
            int tamanho_file = receber.read(buffer);
            if(tamanho_file == -1)break;
            file.write(buffer, 0, tamanho_file);
        }
        file.close();
    }

    private void leituraArquivo(String nome) {
        try{
        //leitura
        BufferedReader br = new BufferedReader (new FileReader(nome));
       
        //enquanto houver mais linhas
        while (br.ready()) {
            //lê a proxima linha
            String linha = br.readLine();
            //faz algo com a linha
            System.out.println(linha);
        }
        br.close();
        System.out.println("\nArquivo lido com sucesso!");
        }
        catch (IOException e) {
            System.out.println("exception occoured"+ e);
            System.out.println("Arquivo não existe.");
         }
    }

    public static void main (String[] args) throws IOException {
        
        Socket connection = null;
        /** Define a host server */
        String host = "frontend";
        /** Define a port */
        int portInfo = 9000;
        int portMensagem = 4000;
        String nodeDestino = null;//node que será enviado o arquivo
        TCPEchoClient tcp = new TCPEchoClient();
        Scanner entrada = new Scanner(System.in);
        char comando;
        String mensagemAEnviar, opcao, nomeArq;
        tcp.TIME0 = System.currentTimeMillis();
        //Estabele conexao com o servidor
        connection = tcp.estabelecerConexao(host, portInfo);

        //
        BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());
        OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");

        //Le o nome do arquivo
        System.out.println("Entre com o nome do arquivo buscado: ");
        nomeArq = entrada.nextLine();
        //Le o nome do arquivo
        System.out.println("O que deseja fazer com o arquivo: (C - criar,L - leitura,E - excluir,M - mover)");
        opcao = entrada.nextLine();
        comando = opcao.charAt(0);
        mensagemAEnviar = opcao + InetAddress.getLocalHost().getHostName() + '*' + nomeArq + '#';
        System.out.println(mensagemAEnviar);
        
        //Envia a mensagem para o servidor
        osw.write(mensagemAEnviar);//Enviando o dado...   
        
        tcp.TIME1 = System.currentTimeMillis();
        
        long resultado_Tempo = tcp.TIME1 - tcp.TIME0;
        System.out.println(resultado_Tempo);
        
        //Vê as opcoes
        if(comando == 'C'){//criar arquivo no node de destino e atualizar a lista do server
            connection.close();
            System.out.println("Qual e o node de destino?");
            nodeDestino = entrada.nextLine();
//            
//            //Envia em qual node irá ser salvo
//            osw.write(nodeDestino);//Enviando o dado...
//            osw.flush();
            
            //Configuracao com node que será criado o arquivo
            Socket connection2 = tcp.estabelecerConexao(nodeDestino, portMensagem);
            BufferedOutputStream bos2 = new BufferedOutputStream(connection2.getOutputStream());
            OutputStreamWriter osw2 = new OutputStreamWriter(bos, "US-ASCII");
            //Envia em qual node irá ser salvo
            osw2.write(nodeDestino);//Enviando o dado...
            //osw2.flush();
            connection2.close();
        }else{
            //Agora recebe o nome do node que contem o arquivo
            nodeDestino = tcp.requisicaoNomeNodeDestino(connection);
            connection.close();
            /*Para conexao com o node de destino e ver oque fazer com o arquivo*/
            //Abre outra conexao, dessa vez com o node de destino
            connection = tcp.estabelecerConexao(nodeDestino, portMensagem);
            tcp.enviarNomeArquivoParaNodeDestino(connection, mensagemAEnviar);
            //Tomada de decisao
            tcp.tomarDecisao(comando, nomeArq, nodeDestino, connection);
            connection.close();
        }
    }
        

}
